Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Buffer Factory: Configuration of the minimum account size to track. #17562

Merged
merged 11 commits into from
Aug 12, 2021

Conversation

KBaichoo
Copy link
Contributor

@KBaichoo KBaichoo commented Aug 2, 2021

We can now configure the minimum account size to track.

Signed-off-by: Kevin Baichoo [email protected]

Commit Message: Buffer Factory: Configuration of the minimum account size to track.
Additional Description:
Risk Level: low
Testing: unit test
Docs Changes: NA
Release Notes: NA -- the feature isn't entirely user-facing. The documentation and release note changes are already finished in a PR that builds off of this. See: https://github.com/KBaichoo/envoy/pull/111/files#diff-c69815663eb82a9e98598ce5dc2c55bc7a4b0b180dd7fe188ef1227bdab9160c
Related Issue #15791

@repokitteh-read-only
Copy link

CC @envoyproxy/api-shepherds: Your approval is needed for changes made to api/envoy/.
envoyproxy/api-shepherds assignee is @markdroth
CC @envoyproxy/api-watchers: FYI only for changes made to api/envoy/.

🐱

Caused by: #17562 was opened by KBaichoo.

see: more, trace.

@KBaichoo
Copy link
Contributor Author

KBaichoo commented Aug 2, 2021

/assign @antoniovicente

PTAL

@markdroth markdroth assigned htuch and unassigned markdroth Aug 2, 2021
Copy link
Member

@htuch htuch left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

API review

@@ -219,6 +219,8 @@ message Bootstrap {
(udpa.annotations.security).configure_for_untrusted_upstream = true
];

BufferFactoryConfig buffer_factory_config = 33;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Needs comment. Should this be placed in some other message like ResourceTrackingConfig for future proofing? Not sure what else we anticipate here, but not a big fan of tons of knobs on the top-level bootstrap.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

// Configuration for the Buffer Factories that create Buffers and Accounts.
message BufferFactoryConfig {
// The minimum account size at which Envoy starts tracking a stream.
// This *MUST* be a power of two.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not make it the exponent then?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea, will go with this.

Copy link
Contributor

@antoniovicente antoniovicente left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for review delays. Main comment is how these new config fields would interact with overload manager actions.

// [account_tracking_threshold_bytes, 2 * account_tracking_threshold_bytes).
// With the 8th bucket tracking accounts
// >= 128 * account_tracking_threshold_bytes.
uint32 account_tracking_threshold_bytes = 1 [(validate.rules).uint32 = {gt: 0}];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be possible to add a proto validator to verify it is a power of 2?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's currently not supported by protogen validate, will go with exponent as htuch suggested.


// Configuration for the Buffer Factories that create Buffers and Accounts.
message BufferFactoryConfig {
// The minimum account size at which Envoy starts tracking a stream.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Worth providing config options for both the min and max thresholds?

Copy link
Contributor Author

@KBaichoo KBaichoo Aug 3, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think min with 8 buckets based on power of two should be sufficient for now -- e.g. if first bucket's range is [Y, 2Y) the final bucket will be >= 128 * Y.

@@ -642,3 +644,16 @@ message CustomInlineHeader {
// The type of the header that is expected to be set as the inline header.
InlineHeaderType inline_header_type = 2 [(validate.rules).enum = {defined_only: true}];
}

// Configuration for the Buffer Factories that create Buffers and Accounts.
message BufferFactoryConfig {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are there other places in the config where we should consider configuring this? HttpConnectionManager or listener may make sense. The issue is that each permutation of the config would require a separate set of tracker objects.

Also, what would the overload manager config for this functionality would look like? This new config field feels like typed config for the overload manager reset streams action.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's one buffer factory per worker. I think configuring it on something dynamic e.g. listeners would add additional complexity.

I see the argument for this being a typed config for an overload manager reset stream action, would need to do a good amount of plumbing to expose the overload manager to the API object from which I can create the watermark factory. Of the 6 overload actions here: https://www.envoyproxy.io/docs/envoy/latest/configuration/operations/overload_manager/overload_manager#overload-actions only one uses additional typed_config (reduce_timeouts)

See: https://github.com/KBaichoo/envoy/pull/111/files#diff-c69815663eb82a9e98598ce5dc2c55bc7a4b0b180dd7fe188ef1227bdab9160cR170-R190 for how the overload manager could leverage this without additional typed config

I also see the benefit of tracking being independent e.g. stats monitoring the buckets

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking into the feasibility of this in an overload_manager action:

api_impl creates watermark buffer factories through its creation of dispatchers. The watermark buffer factories should know the minimum account sizes to track at creation.

If we shift the knowledge of the minimum account size to an overload manager action, then the api_impl needs access to the overload manager in order to create dispatchers. But the overload manager needs the api object in its ctor.

Going down this route seems very convoluted given that dependence.

We could have instead the api_impl parse some of the overload manager config from the bootstrap to get the knowledge, but that also seems wrong since the module is leaking.

As such I'm leaning towards wrapping this in ResourceTrackingConfig or similar as htuch recommends to future proof it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about having these parameters are part of the toplevel OverloadManager proto since they are related to that functional area? The OverloadManager proto is already a parsed member in the bootstrap. The config option would go here:

google.protobuf.Duration refresh_interval = 1;

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, moved to top level of the Overload Manager config.

@@ -195,10 +215,11 @@ BufferMemoryAccountImpl::createAccount(WatermarkBufferFactory* factory,
}

int BufferMemoryAccountImpl::balanceToClassIndex() {
const uint64_t shifted_balance = buffer_memory_allocated_ >> 20; // shift by 1MB.
static uint32_t bitshift = factory_->bitshift();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean const?
Use of static here is sure to cause problems in tests as test cases beyond the first would effectively ignore config changes.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prematurely optimized will make it const instead.

Signed-off-by: Kevin Baichoo <[email protected]>
Signed-off-by: Kevin Baichoo <[email protected]>
@KBaichoo
Copy link
Contributor Author

KBaichoo commented Aug 5, 2021

/retest

@repokitteh-read-only
Copy link

Retrying Azure Pipelines:
Retried failed jobs in: envoy-presubmit

🐱

Caused by: a #17562 (comment) was created by @KBaichoo.

see: more, trace.

Copy link
Member

@htuch htuch left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/lgtm api

@repokitteh-read-only repokitteh-read-only bot removed the api label Aug 6, 2021
@@ -206,6 +212,7 @@ class WatermarkBufferFactory : public WatermarkFactory {
using MemoryClassesToAccountsSet = std::array<absl::flat_hash_set<BufferMemoryAccountSharedPtr>,
BufferMemoryAccountImpl::NUM_MEMORY_CLASSES_>;
MemoryClassesToAccountsSet size_class_account_sets_;
uint32_t bitshift_;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: const

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A comment would be good.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

: WatermarkBufferFactory([min_tracking_bytes]() {
auto config = envoy::config::bootstrap::v3::ResourceTrackingConfig::BufferFactoryConfig();
if (min_tracking_bytes > 0) {
config.set_minimum_account_to_track_power_of_two(absl::bit_width(min_tracking_bytes));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you take minimum_account_to_track_power_of_two as a constructor argument instead of min_tracking_bytes?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.


TEST(WatermarkBufferFactoryTest, DefaultsToTrackingAccountsGreaterThanOrEqualTo256KB) {
TrackedWatermarkBufferFactory factory;
EXPECT_EQ(factory.bitshift(), 18);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems like the previous 2 test cases are testing the behavior of a test-only class.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I invoke the WatermarkBufferFactory ctor directly now.

// 2^(minimum_account_to_track_power_of_two + 1)) bytes.
// With the 8th bucket tracking accounts
// >= 128 * 2^minimum_account_to_track_power_of_two.
uint32 minimum_account_to_track_power_of_two = 1 [(validate.rules).uint32 = {lte: 63 gt: 0}];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Setting the exponent to 1 may not produce great results either since it would only track up to 128 bytes, don't know if it would be worth using a more reasonable floor like 1024 bytes.

Setting to 63 effectively disables all tracking since it would result in a bit shift that would 0 out all reasonable buffer byte sizes. I guess this is a reasonable max.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Floor is now 1024 bytes.

// [2^minimum_account_to_track_power_of_two,
// 2^(minimum_account_to_track_power_of_two + 1)) bytes.
// With the 8th bucket tracking accounts
// >= 128 * 2^minimum_account_to_track_power_of_two.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should describe the default behavior. Another related question is what the default behavior should be: Some specific value or no resource tracking.

"No resource tracking" seems like the more reasonable default.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done the default is to effectively disable tracking.

@@ -642,3 +644,16 @@ message CustomInlineHeader {
// The type of the header that is expected to be set as the inline header.
InlineHeaderType inline_header_type = 2 [(validate.rules).enum = {defined_only: true}];
}

// Configuration for the Buffer Factories that create Buffers and Accounts.
message BufferFactoryConfig {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about having these parameters are part of the toplevel OverloadManager proto since they are related to that functional area? The OverloadManager proto is already a parsed member in the bootstrap. The config option would go here:

google.protobuf.Duration refresh_interval = 1;

@repokitteh-read-only repokitteh-read-only bot added api and removed waiting labels Aug 9, 2021
Copy link
Contributor Author

@KBaichoo KBaichoo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the review @antoniovicente

@@ -206,6 +212,7 @@ class WatermarkBufferFactory : public WatermarkFactory {
using MemoryClassesToAccountsSet = std::array<absl::flat_hash_set<BufferMemoryAccountSharedPtr>,
BufferMemoryAccountImpl::NUM_MEMORY_CLASSES_>;
MemoryClassesToAccountsSet size_class_account_sets_;
uint32_t bitshift_;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

: WatermarkBufferFactory([min_tracking_bytes]() {
auto config = envoy::config::bootstrap::v3::ResourceTrackingConfig::BufferFactoryConfig();
if (min_tracking_bytes > 0) {
config.set_minimum_account_to_track_power_of_two(absl::bit_width(min_tracking_bytes));
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

// 2^(minimum_account_to_track_power_of_two + 1)) bytes.
// With the 8th bucket tracking accounts
// >= 128 * 2^minimum_account_to_track_power_of_two.
uint32 minimum_account_to_track_power_of_two = 1 [(validate.rules).uint32 = {lte: 63 gt: 0}];
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Floor is now 1024 bytes.

// [2^minimum_account_to_track_power_of_two,
// 2^(minimum_account_to_track_power_of_two + 1)) bytes.
// With the 8th bucket tracking accounts
// >= 128 * 2^minimum_account_to_track_power_of_two.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done the default is to effectively disable tracking.


TEST(WatermarkBufferFactoryTest, DefaultsToTrackingAccountsGreaterThanOrEqualTo256KB) {
TrackedWatermarkBufferFactory factory;
EXPECT_EQ(factory.bitshift(), 18);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I invoke the WatermarkBufferFactory ctor directly now.

@@ -642,3 +644,16 @@ message CustomInlineHeader {
// The type of the header that is expected to be set as the inline header.
InlineHeaderType inline_header_type = 2 [(validate.rules).enum = {defined_only: true}];
}

// Configuration for the Buffer Factories that create Buffers and Accounts.
message BufferFactoryConfig {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, moved to top level of the Overload Manager config.

@KBaichoo
Copy link
Contributor Author

/retest

@repokitteh-read-only
Copy link

Retrying Azure Pipelines:
Retried failed jobs in: envoy-presubmit

🐱

Caused by: a #17562 (comment) was created by @KBaichoo.

see: more, trace.

Copy link
Contributor

@yanavlasov yanavlasov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/wait

// With the 8th bucket tracking accounts
// >= 128 * 2^minimum_account_to_track_power_of_two.
//
// Setting this to 63 effectively disables all tracking since the resulting
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this be 64 - 8 = 56 ? Otherwise some higher order buckets will not be tracked.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sgtm will set the max to in pgv to 56 as that's the last valid config that'd use all 8 buckets (56-63). Don't expect that we'll have any buffers using 2^56 bytes in practice.

Omitting the field effectively disables it.

/**
* @return the bootstrap Envoy started with.
*/
virtual const envoy::config::bootstrap::v3::Bootstrap& bootstrap() const PURE;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think dispatchers are always allocated through the Api interface. In this case you do not need this method. Just save the bootstrap in the ApiImpl and then pass buffer config to the dispatcher constructor.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dispatchers are created outside of the Api interface in certain places.

Given that the Api has the information, and is already plumbed through the 3 ctors of the dispatcher, avoiding telescoping ctor by having the object with the information expose it seemed like the way to go.

@yanavlasov yanavlasov self-assigned this Aug 11, 2021
Copy link
Contributor Author

@KBaichoo KBaichoo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the review @yanavlasov

// With the 8th bucket tracking accounts
// >= 128 * 2^minimum_account_to_track_power_of_two.
//
// Setting this to 63 effectively disables all tracking since the resulting
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sgtm will set the max to in pgv to 56 as that's the last valid config that'd use all 8 buckets (56-63). Don't expect that we'll have any buffers using 2^56 bytes in practice.

Omitting the field effectively disables it.

/**
* @return the bootstrap Envoy started with.
*/
virtual const envoy::config::bootstrap::v3::Bootstrap& bootstrap() const PURE;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dispatchers are created outside of the Api interface in certain places.

Given that the Api has the information, and is already plumbed through the 3 ctors of the dispatcher, avoiding telescoping ctor by having the object with the information expose it seemed like the way to go.

Copy link
Contributor

@antoniovicente antoniovicente left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks.

@KBaichoo
Copy link
Contributor Author

@htuch for api-review round 2

Copy link
Member

@htuch htuch left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/lgtm api

@htuch htuch merged commit b51f0ea into envoyproxy:main Aug 12, 2021
dubious90 pushed a commit to envoyproxy/nighthawk that referenced this pull request Aug 18, 2021
- refactoring `ProcessImpl`, creating a named constructor that allows us to
  create bootstrap initially and pass it to `Envoy::Api::Impl()` as required
  since envoyproxy/envoy#17562. Specifically:
  - Moving method `ProcessImpl::determineConcurrency()` out of the ProcessImpl class so that it can be used during its construction.
  - Moving code that extracts URIs from `process_impl.cc` into `process_bootstrap.cc`.
  - Adding a previously missing test case `CreatesBootstrapForH1RespectingPortInUri` into `process_bootstrap_test.cc`.
  - Removing a TODO that incorrectly indicated URI DNS resolution is optional. Envoy [requires](https://github.com/envoyproxy/envoy/blob/716ee8abc526d51f07ed6d3c2a5aa8a3b2481d9d/api/envoy/config/core/v3/address.proto#L64-L67) resolved IPs in the Bootstrap for cluster of type STATIC.
  - Creating a named constructor for `ProcessImpl` that creates the `Envoy::Api::Api` with an empty Bootstrap that is then replaced with the one generated. See an inline comment for explanation.
  - Moving callers onto the named constructor and making the original constructor of `ProcessImpl` private.
- no changes to `.bazelrc`, `.bazelversion`, `run_envoy_docker.sh`.

Signed-off-by: Jakub Sobon <[email protected]>
leyao-daily pushed a commit to leyao-daily/envoy that referenced this pull request Sep 30, 2021
…nvoyproxy#17562)

Risk Level: low
Testing: unit test
Docs Changes: NA
Release Notes: NA -- the feature isn't entirely user-facing. The documentation and release note changes are already finished in a PR that builds off of this. See: https://github.com/KBaichoo/envoy/pull/111/files#diff-c69815663eb82a9e98598ce5dc2c55bc7a4b0b180dd7fe188ef1227bdab9160c
Related Issue envoyproxy#15791

Signed-off-by: Kevin Baichoo <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants